package corewarsxxi.gui;

import corewarsxxi.logic.*;
import java.awt.Color;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URI;
import java.util.Arrays;
import java.util.Random;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.border.LineBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.filechooser.FileFilter;

/**
 *
 * @author ei10139
 */
public final class WarriorMaker extends JFrame
{
    protected static final Icon iWarriorNew = new ImageIcon("img/warrior_new.png");
    protected static final Icon iWarriorLoad = new ImageIcon("img/warrior_load.png");
    protected static final Icon iWarriorSave = new ImageIcon("img/warrior_save.png");
    protected static final Icon iWarriorSaveActive = new ImageIcon("img/warrior_save_active.png");
    protected static final Icon iClose = new ImageIcon("img/close.png");
    protected static final Icon iCloseActive = new ImageIcon("img/close_active.png");
    protected static final Icon iMoveUp = new ImageIcon("img/move_up.png");
    protected static final Icon iMoveDown = new ImageIcon("img/move_down.png");
    protected static final Icon iDelete = new ImageIcon("img/delete.png");
    protected static final Icon iStar = new ImageIcon("img/about_star.png");
    protected static final Icon iStarActive = new ImageIcon("img/about_star_active.png");
    protected static final Icon iLink= new ImageIcon("img/link.png");
    protected static final Icon iHelp = new ImageIcon("img/help.png");

    final AddressingMode[] AddressingModes = new AddressingMode[]
                    {AMDirect.self, AMImmediate.self, AMIndirect.self,
                     AMPostincrement.self, AMPredecrement.self};

    final JList lInstructions = new JList();
    final JTextField tfWarriorName = new JTextField();
    DefaultListModel lInstructionsModel = new DefaultListModel();
    Warrior w = new Warrior("");

    IntTextField ocetfA, ocetfB;
    JComboBox ocecbA, ocecbB;
    final JButton ocebMoveUp, ocebMoveDown, ocebDelete;

    public WarriorMaker()
    {
        super("Core Wars XXI - Warrior Maker");

        try {
            UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
        } catch (Exception e) {
        }
        // -----------------------------------------------
        // ------------------- MENU BAR ------------------
        // -----------------------------------------------

        JMenuBar menuBar = new JMenuBar();
            final JMenu jmWarrior = new JMenu("Warrior");
            jmWarrior.setMnemonic(KeyEvent.VK_W);
                // ----------------- NEW WARRIOR -----------------
                JMenuItem jmiWarriorNew = new JMenuItem("New Warrior", iWarriorNew);
                jmiWarriorNew.setMnemonic(KeyEvent.VK_N);
                jmiWarriorNew.setAccelerator(KeyStroke.getKeyStroke(
                    KeyEvent.VK_N, ActionEvent.ALT_MASK));
                jmiWarriorNew.addActionListener(alWarriorNew);

                // ----------------- OPEN WARRIOR ----------------
                JMenuItem jmiWarriorOpen = new JMenuItem("Open Warrior", iWarriorLoad);
                jmiWarriorOpen.setMnemonic(KeyEvent.VK_O);
                jmiWarriorOpen.setAccelerator(KeyStroke.getKeyStroke(
                    KeyEvent.VK_O, ActionEvent.ALT_MASK));
                jmiWarriorOpen.addActionListener(alWarriorLoad);

                // ------------- OPEN RECENT WARRIOR -------------
                JMenu jmWarriorOpenR = new JMenu("Open Recent Warrior");
                jmWarriorOpenR.setMnemonic(KeyEvent.VK_R);
                jmWarriorOpenR.setEnabled(false); // TODO: Might not do it..

                // ----------------- SAVE WARRIOR ----------------
                final JMenuItem jmiWarriorSave = new JMenuItem("Save Warrior", iWarriorSave);
                jmiWarriorSave.setMnemonic(KeyEvent.VK_S);
                jmiWarriorSave.setAccelerator(KeyStroke.getKeyStroke(
                    KeyEvent.VK_S, ActionEvent.ALT_MASK));
                jmiWarriorSave.addActionListener(alWarriorSave);
                jmiWarriorSave.addMouseListener(new MouseListener() {
                    public void mouseClicked(MouseEvent e) {}
                    public void mousePressed(MouseEvent e) {}
                    public void mouseReleased(MouseEvent e) {}

                    public void mouseEntered(MouseEvent e) {
                        jmiWarriorSave.setIcon(iWarriorSaveActive);
                    }
                    public void mouseExited(MouseEvent e) {
                        jmiWarriorSave.setIcon(iWarriorSave);
                    }
                });

                // -------------------- CLOSE --------------------
                final JMenuItem jmiWarriorClose = new JMenuItem("Close", iClose);
                jmiWarriorClose.setMnemonic(KeyEvent.VK_C);
                jmiWarriorClose.setAccelerator(KeyStroke.getKeyStroke(
                    KeyEvent.VK_C, ActionEvent.ALT_MASK));

                jmiWarriorClose.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                            WarriorMaker.this.dispose();
                    }
                });
                jmiWarriorClose.addMouseListener(new MouseListener() {
                    public void mouseClicked(MouseEvent e) {}
                    public void mousePressed(MouseEvent e) {}
                    public void mouseReleased(MouseEvent e) {}
                    public void mouseEntered(MouseEvent e) {
                        jmiWarriorClose.setIcon(iCloseActive);
                    }
                    public void mouseExited(MouseEvent e) {
                        jmiWarriorClose.setIcon(iClose);
                    }
                });

            jmWarrior.add(jmiWarriorNew);
            jmWarrior.addSeparator();
            jmWarrior.add(jmiWarriorOpen);
            jmWarrior.add(jmWarriorOpenR);
            jmWarrior.addSeparator();
            jmWarrior.add(jmiWarriorSave);
            jmWarrior.addSeparator();
            jmWarrior.add(jmiWarriorClose);

            JMenu jmHelp = new JMenu("Help");
            jmHelp.setMnemonic(KeyEvent.VK_H);
                final JMenuItem jmiHelpOnlineSupport = new JMenuItem("Online Help & Support", iHelp);
                jmiHelpOnlineSupport.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        try {
                            Desktop.getDesktop().browse(new URI("http://vyznev.net/corewar/guide.html"));
                        } catch (Exception ex) {
                            JOptionPane.showMessageDialog(WarriorMaker.this,
                                "Error openning browser:\n" + ex.getMessage(),
                                "Error", JOptionPane.ERROR_MESSAGE);
                        }
                    }
                });

                final JMenuItem jmiHelpAbout = new JMenuItem("About Core Wars XXI", iStar);
                jmiHelpAbout.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    JOptionPane.showMessageDialog(WarriorMaker.this,
                            "This game was proudly coded by\n" +
                            "Luís Fonseca, ei10139 @ FEUP.",
                            "About Core Wars XXI",
                            JOptionPane.INFORMATION_MESSAGE);
                    }
                });
                jmiHelpAbout.addMouseListener(new MouseListener() {
                    public void mouseClicked(MouseEvent e) {}
                    public void mousePressed(MouseEvent e) {}
                    public void mouseReleased(MouseEvent e) {}
                    public void mouseEntered(MouseEvent e) {
                        jmiHelpAbout.setIcon(iStarActive);
                    }
                    public void mouseExited(MouseEvent e) {
                        jmiHelpAbout.setIcon(iStar);
                    }
                });

            jmHelp.add(jmiHelpOnlineSupport);
            jmHelp.addSeparator();
            jmHelp.add(jmiHelpAbout);

        menuBar.add(jmWarrior);
        menuBar.add(jmHelp);

        super.setJMenuBar(menuBar);
        // -----------------------------------------------
        // ------------------- TOOL BAR ------------------
        // -----------------------------------------------
        JToolBar toolBar = new JToolBar("Main Toolbar");

        JButton jbWarriorNew = new JButton(iWarriorNew);
        JButton jbWarriorLoad = new JButton(iWarriorLoad);
        JButton jbWarriorSave = new JButton(iWarriorSave);
        jbWarriorNew.addActionListener(alWarriorNew);
        jbWarriorLoad.addActionListener(alWarriorLoad);
        jbWarriorSave.addActionListener(alWarriorSave);
        jbWarriorNew.setToolTipText("Create New Warrior...");
        jbWarriorLoad.setToolTipText("Load Existing Warrior...");
        jbWarriorSave.setToolTipText("Save Current Warrior...");

        toolBar.add(jbWarriorNew);
        toolBar.add(jbWarriorLoad);
        toolBar.add(jbWarriorSave);
        toolBar.setEnabled(false);


        // -----------------------------------------------
        // -------------------- PANEL --------------------
        // -----------------------------------------------
        JPanel jp = new JPanel();
        GroupLayout layout = new GroupLayout(jp);

        JLabel lbWarriorName = new JLabel("Warrior Name:");
        lbWarriorName.setFont(new Font("Segoe UI", Font.PLAIN, 12));

        String wName = randomName();
        w.setName(wName);
        tfWarriorName.setText(wName);
        tfWarriorName.setFont(new Font("Calibri", Font.PLAIN, 13));
        tfWarriorName.addKeyListener(new KeyListener() {
            public void keyTyped(KeyEvent e) {}
            public void keyPressed(KeyEvent e) {}
            public void keyReleased(KeyEvent e) {
                String name = tfWarriorName.getText();
                if(name.length() == 0)
                    tfWarriorName.setText(name = randomName());
                
                w.setName(name);
            }
        });

        // ---------------- PROGRAMING PAD ----------------
        JPanel jpProgPad = new JPanel();

        // Instructions
        lInstructions.setModel(lInstructionsModel);
        lInstructions.setFont(new Font("Courier New", Font.PLAIN, 13));
        lInstructions.addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                MemoryCell mc = (MemoryCell) lInstructions.getSelectedValue();
                if(mc == null)
                    return;
                
                ocecbA.setSelectedItem(mc.getaField().getAddressingMode().toString(true));
                ocecbB.setSelectedItem(mc.getbField().getAddressingMode().toString(false));
                ocetfA.setText(mc.getaField().toString().substring(1));
                ocetfB.setText(mc.getbField().toString().substring(1));

                int index = lInstructions.getSelectedIndex();
                fieldsSetEnabled(true);
                ocebMoveUp.setEnabled(index != 0);
                ocebMoveDown.setEnabled(index != lInstructionsModel.size() - 1);
            }
        });


        final JScrollPane spInstructions =
                new JScrollPane(lInstructions,
                    ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
                    ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);

        lInstructions.setPreferredSize(new Dimension(250, 200));
        spInstructions.setPreferredSize(new Dimension(300, 200));

        jpProgPad.setFont(new Font("Segoe UI", Font.PLAIN, 13));
        jpProgPad.setBorder(BorderFactory.createTitledBorder("Programming Pad"));


        // ----------------- EDIT INSTRUCTION
        JPanel jpOpCodeEdit = new JPanel();
        GroupLayout layoutOpCodeEdit = new GroupLayout(jpOpCodeEdit);
        layoutOpCodeEdit.setAutoCreateGaps(true);
        layoutOpCodeEdit.setAutoCreateContainerGaps(true);

        JLabel ocelA = new JLabel("A:");
        JLabel ocelB = new JLabel("B:");
        ocelA.setFont(new Font("Segoe UI", Font.PLAIN, 13));
        ocelB.setFont(new Font("Segoe UI", Font.PLAIN, 13));

        ocecbA = new JComboBox();
        ocecbB = new JComboBox();
        ocecbA.setEnabled(false);
        ocecbB.setEnabled(false);
        ocecbA.setFont(new Font("Segoe UI", Font.PLAIN, 13));
        ocecbB.setFont(new Font("Segoe UI", Font.PLAIN, 13));
        ocecbA.setPreferredSize(new Dimension(37, 22));
        ocecbB.setPreferredSize(new Dimension(37, 22));
        for(AddressingMode am : AddressingModes) {
            ocecbA.addItem(am.toString(true));
            ocecbB.addItem(am.toString(false));
        }
        ItemListener ocecbItemListenner = new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
                int index = lInstructions.getSelectedIndex();
                if(index == -1)
                    return;

                boolean aField = e.getSource().equals(ocecbA);
                String item = (String)e.getItem();
                for(AddressingMode am : AddressingModes) {
                    if(am.toString(aField).equals(item)) {
                        if(aField)
                            ((MemoryCell) lInstructionsModel.getElementAt(index))
                                .getaField().changeAddressingMode(am);
                        else((MemoryCell) lInstructionsModel.getElementAt(index))
                                .getbField().changeAddressingMode(am, false);

                        lInstructions.repaint();
                        return;
                    }
                }
            }
        };
        ocecbA.addItemListener(ocecbItemListenner);
        ocecbB.addItemListener(ocecbItemListenner);


        ocetfA = new IntTextField(0, 9);
        ocetfB = new IntTextField(0, 9);
        ocetfA.setEnabled(false);
        ocetfB.setEnabled(false);
        ocetfA.setFont(new Font("Calibri", Font.PLAIN, 13));
        ocetfA.setFont(new Font("Calibri", Font.PLAIN, 13));
        ocetfA.addKeyListener(new KeyListener() {
            public void keyTyped(KeyEvent e) {}
            public void keyPressed(KeyEvent e) {}
            public void keyReleased(KeyEvent e) {
                MemoryCell mc = (MemoryCell) lInstructions.getSelectedValue();
                if(mc == null)
                    return;

                mc.getaField().setValue(((IntTextField) e.getSource()).getValue());
                lInstructions.repaint();
            }
        });
        ocetfB.addKeyListener(new KeyListener() {
            public void keyTyped(KeyEvent e) {}
            public void keyPressed(KeyEvent e) {}
            public void keyReleased(KeyEvent e) {
                MemoryCell mc = (MemoryCell) lInstructions.getSelectedValue();
                if(mc == null)
                    return;
                
                mc.getbField().setValue(((IntTextField) e.getSource()).getValue());
                lInstructions.repaint();
            }
        });

        ocebMoveUp = new JButton("Move up", iMoveUp);
        ocebMoveDown = new JButton("Move Down", iMoveDown);
        ocebDelete = new JButton("Remove Instruction", iDelete);
        ocebDelete.setPreferredSize(new Dimension(210, 20));
        ocebDelete.setEnabled(false);
        ocebDelete.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                int index = lInstructions.getSelectedIndex();
                if(index == -1)
                    return;

                lInstructionsModel.removeElementAt(index);
                lInstructions.repaint();
                fieldsSetEnabled(false);
            }
        });


        ocebMoveUp.setEnabled(false);
        ocebMoveDown.setEnabled(false);
        ActionListener ocealMoves = new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                int index = lInstructions.getSelectedIndex();
                if(index == -1)
                    return;

                int dir = ocebMoveUp.equals(e.getSource()) ? -1 : 1;

                Object temp = lInstructionsModel.getElementAt(index + dir);
                lInstructionsModel.setElementAt(lInstructionsModel.getElementAt(index), index + dir);
                lInstructionsModel.setElementAt(temp, index);
                lInstructions.setSelectedIndex(index + dir);
                lInstructions.repaint();
            }
        };
        ocebMoveUp.addActionListener(ocealMoves);
        ocebMoveDown.addActionListener(ocealMoves);

        layoutOpCodeEdit.setHorizontalGroup(layoutOpCodeEdit.createParallelGroup()
                .addGroup(layoutOpCodeEdit.createSequentialGroup()
                    .addGroup(layoutOpCodeEdit.createParallelGroup()
                        .addComponent(ocelA)
                        .addComponent(ocelB))
                    .addGroup(layoutOpCodeEdit.createParallelGroup()
                        .addComponent(ocecbA)
                        .addComponent(ocecbB))
                    .addGroup(layoutOpCodeEdit.createParallelGroup()
                        .addComponent(ocetfA)
                        .addComponent(ocetfB)))
                .addGroup(layoutOpCodeEdit.createSequentialGroup()
                    .addComponent(ocebMoveUp)
                    .addComponent(ocebMoveDown))
                .addGroup(layoutOpCodeEdit.createParallelGroup()
                    .addComponent(ocebDelete)));

        layoutOpCodeEdit.setVerticalGroup(layoutOpCodeEdit.createSequentialGroup()
                .addGroup(layoutOpCodeEdit.createParallelGroup(Alignment.BASELINE)
                    .addComponent(ocelA)
                    .addComponent(ocecbA)
                    .addComponent(ocetfA))
                .addGroup(layoutOpCodeEdit.createParallelGroup(Alignment.BASELINE)
                    .addComponent(ocelB)
                    .addComponent(ocecbB)
                    .addComponent(ocetfB))
                .addGroup(layoutOpCodeEdit.createParallelGroup(Alignment.BASELINE)
                    .addComponent(ocebMoveUp)
                    .addComponent(ocebMoveDown))
                .addGroup(layoutOpCodeEdit.createSequentialGroup()
                    .addComponent(ocebDelete)));
        layoutOpCodeEdit.linkSize(SwingConstants.HORIZONTAL, ocecbA);
        layoutOpCodeEdit.linkSize(SwingConstants.HORIZONTAL, ocecbB);
        layoutOpCodeEdit.linkSize(SwingConstants.HORIZONTAL, ocebDelete);

        jpOpCodeEdit.setFont(new Font("Segoe UI", Font.PLAIN, 13));
        jpOpCodeEdit.setBorder(BorderFactory.createTitledBorder("Instruction Editor"));
        jpOpCodeEdit.setLayout(layoutOpCodeEdit);

        GroupLayout layoutProgPad = new GroupLayout(jpProgPad);
        layoutProgPad.setAutoCreateGaps(true);
        layoutProgPad.setAutoCreateContainerGaps(true);

        layoutProgPad.setHorizontalGroup(
                layoutProgPad.createSequentialGroup()
                .addComponent(spInstructions)
                .addComponent(jpOpCodeEdit));
        layoutProgPad.setVerticalGroup(
                layoutProgPad.createParallelGroup()
                .addComponent(spInstructions)
                .addGap(8)
                .addComponent(jpOpCodeEdit));
        layoutProgPad.linkSize(SwingConstants.HORIZONTAL, spInstructions);
        jpProgPad.setLayout(layoutProgPad);

        // ----------------- OPCODE PANEL -----------------
        JPanel jpOpCode = new JPanel();
        
        final JList lOpCode =
                new JList(
                    new Object[] {add.self, cmp.self, dat.self, djn.self, jmn.self, jmp.self,
                                  jmz.self, mov.self, nop.self, slt.self, spl.self, sub.self});
        lOpCode.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        lOpCode.setFont(new Font("Segoe UI", Font.PLAIN, 13));
        lOpCode.setPreferredSize(new Dimension(75, 30));
        lOpCode.setDragEnabled(true);
        lOpCode.setBorder(new LineBorder(Color.lightGray, 1, true));
        lInstructions.setDropTarget(new DropTarget(lOpCode, new DropTargetListener() {
            public void dragEnter(DropTargetDragEvent dtde) {}
            public void dragOver(DropTargetDragEvent dtde) {}
            public void dropActionChanged(DropTargetDragEvent dtde) {}
            public void dragExit(DropTargetEvent dte) {}
            public void drop(DropTargetDropEvent dtde) {
                MemoryCell mc = new MemoryCell(
                                    (OpCode) lOpCode.getSelectedValue(),
                                    new MemoryField(), new MemoryField());
                int offsetY = dtde.getLocation().y;
                if(offsetY > 19 * lInstructionsModel.size())
                    lInstructionsModel.addElement(mc);
                else
                    lInstructionsModel.add(offsetY / 19 + 1, mc);

                lInstructions.setPreferredSize(new Dimension(250, 19 * lInstructionsModel.size()));
                spInstructions.setPreferredSize(new Dimension(300, 19 * lInstructionsModel.size()));
            }
        }));


        GroupLayout layoutOpCode = new GroupLayout(jpOpCode);
        layoutOpCode.setAutoCreateGaps(true);
        layoutOpCode.setAutoCreateContainerGaps(true);

        layoutOpCode.linkSize(SwingConstants.HORIZONTAL, lOpCode);

        layoutOpCode.setHorizontalGroup(
                layoutOpCode.createSequentialGroup().addComponent(lOpCode));
        layoutOpCode.setVerticalGroup(
                layoutOpCode.createParallelGroup().addComponent(lOpCode));

        jpOpCode.setFont(new Font("Segoe UI", Font.PLAIN, 13));
        jpOpCode.setBorder(BorderFactory.createTitledBorder("Instructions"));
        jpOpCode.setLayout(layoutOpCode);
        
        // ---------------- PANEL LAYOUT ----------------
        layout.setAutoCreateGaps(true);
        layout.setAutoCreateContainerGaps(false);
        layout.setHorizontalGroup(
                layout.createParallelGroup()
                    .addComponent(toolBar)
                    .addGroup(layout.createSequentialGroup()
                        .addGap(14)
                        .addGroup(layout.createSequentialGroup()
                        .addComponent(lbWarriorName)
                        .addGap(40)
                        .addComponent(tfWarriorName))
                        .addGap(20))
                    .addGroup(layout.createSequentialGroup()
                        .addGap(8)
                        .addComponent(jpOpCode)
                        .addComponent(jpProgPad))
                );
        layout.setVerticalGroup(
                layout.createSequentialGroup()
                    .addComponent(toolBar)
                    .addGroup(layout.createParallelGroup(Alignment.BASELINE)
                        .addComponent(lbWarriorName)
                        .addComponent(tfWarriorName))
                    .addGroup(layout.createParallelGroup()
                        .addComponent(jpOpCode)
                        .addComponent(jpProgPad))
                );

        jp.setLayout(layout);
        super.add(jp);
        super.setIconImage(new ImageIcon("img/warrior_new.png").getImage());
        super.pack();
        super.setSize(700, 450);
        super.setMinimumSize(new Dimension(700, 450));
        super.setVisible(true);
        super.setLocationRelativeTo(null);
        super.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        tfWarriorName.requestFocus();
    }
    
    protected static final FileFilter fcRedCodeWarriorFilter = new FileFilter() {
        @Override
        public boolean accept(File f) {
            return f.isDirectory() || f.getName().endsWith(Warrior.savExtention);
        }

        @Override
        public String getDescription() {
            return "RedCode Warrior format (*" + Warrior.savExtention + ")";
        }
    };

    private ActionListener alWarriorNew = new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            // TODO: Confirmar q nao foi alterado

            String name = randomName();
            w = new Warrior(name);
            tfWarriorName.setText(name);
            lInstructionsModel.clear();
            lInstructions.repaint();
            fieldsSetEnabled(false);
        }
    };

    private ActionListener alWarriorSave = new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            w.program.clear();
            w.program.addAll(Arrays.asList(
                                Arrays.copyOf(lInstructionsModel.toArray(),
                                              lInstructionsModel.size(), MemoryCell[].class)));

            JFileChooser fc = new JFileChooser();
            fc.setFileFilter(fcRedCodeWarriorFilter);
            if(fc.showSaveDialog(WarriorMaker.this) != JFileChooser.APPROVE_OPTION)
                return;
            
            try {
                w.save(fc.getSelectedFile().getPath());
            } catch (IOException ex) {
                JOptionPane.showMessageDialog(WarriorMaker.this,
                        "Error writing the file:\n" + ex.getMessage(),
                        "Error", JOptionPane.ERROR_MESSAGE);
                return;
            }
        }
    };

    private ActionListener alWarriorLoad = new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            // TODO: Confirmar q nao foi alterado

            JFileChooser fc = new JFileChooser();
            fc.setFileFilter(fcRedCodeWarriorFilter);
            if(fc.showOpenDialog(WarriorMaker.this) != JFileChooser.APPROVE_OPTION)
                return;

            try {
                w.load(fc.getSelectedFile().getPath());
            } catch (FileNotFoundException ex) {
                JOptionPane.showMessageDialog(WarriorMaker.this,
                        "File not found.:",
                        "Error", JOptionPane.ERROR_MESSAGE);
                return;
            } catch (ClassNotFoundException ex) {
                JOptionPane.showMessageDialog(WarriorMaker.this,
                        "Warrior seems to be corrupt or was saved in a older version of this program.",
                        "Error", JOptionPane.ERROR_MESSAGE);
                return;
            } catch (IOException ex) {
                JOptionPane.showMessageDialog(WarriorMaker.this,
                        "Error reading the file:\n" + ex.getMessage(),
                        "Error", JOptionPane.ERROR_MESSAGE);
                return;
            }

            tfWarriorName.setText(w.getName());
            lInstructionsModel.clear();
            for(MemoryCell mc : w.program)
                lInstructionsModel.addElement(mc);

            lInstructions.repaint();
            fieldsSetEnabled(false);
        }
    };

    private final String[] names1 = new String[] {
        "Sir", "Pink", "Mostard",
        "Beautiful", "Horrible",
        "King", "Awesome"
    };
    private final String[] names2 = new String[] {
        "Bishop", "Teacher", "Dracula", "Lawyer",
        "Coder", "Pharaoh", "Bytter"
    };
    private final String[] names3 = new String[] {
        "-watermelon", "-lemon",
        "-god", "-potato", "-giggity"
    };

    private void fieldsSetEnabled(boolean b)
    {
        ocebMoveUp.setEnabled(b);
        ocebMoveDown.setEnabled(b);
        ocebDelete.setEnabled(b);
        ocecbA.setEnabled(b);
        ocecbB.setEnabled(b);
        ocetfA.setEnabled(b);
        ocetfB.setEnabled(b);
    }

    /**
     * Randomly calculates a name by simply combining Strings from name1,
     * name2, and name3.
     * @return the name
     */
    public String randomName()
    {
        Random r = new Random();
        return names1[r.nextInt(names1.length)] +
               names2[r.nextInt(names2.length)] +
               names3[r.nextInt(names3.length)];
    }

    public static void main(String[] args)
    {
        WarriorMaker debugger = new WarriorMaker();
    }
}